﻿using System.Globalization;

namespace Kaleida.ServiceMonitor.Framework
{
    public class DataSize
    {
        private readonly long valueInBytes;
        private readonly double value;
        private readonly string suffix;

        internal DataSize(double value, string suffix, int valueInBytes)
        {
            this.value = value;
            this.suffix = suffix;
            this.valueInBytes = valueInBytes;
        }

        public static DataSize FromBytes(double bytes)
        {
            return new DataSize(bytes, "bytes", (int) bytes);
        }

        public static DataSize FromKilobytes(double kilobytes)
        {
            return new DataSize(kilobytes, "KB", (int) (kilobytes * 1024));
        }

        public static DataSize FromMegabytes(double megabytes)
        {
            return new DataSize(megabytes, "MB", (int) (megabytes * 1024 * 1024));
        }

        public static DataSize FromGigabytes(double gigabytes)
        {
            return new DataSize(gigabytes, "GB", (int) (gigabytes * 1024 * 1024 * 1024));
        }

        public static DataSize Parse(string text)
        {
            return text.ToDataSize();
        }

        public double Value
        {
            get { return value; }
        }

        public string Suffix
        {
            get { return suffix; }
        }

        public long ValueInBytes
        {
            get { return valueInBytes; }
        }

        public double ValueInKilobytes
        {
            get { return valueInBytes / 1024.0; }
        }

        public double ValueInMegabytes
        {
            get { return ValueInKilobytes / 1024.0; }
        }

        public double ValueInGigabytes
        {
            get { return ValueInMegabytes / 1024.0; }
        }

        public override string ToString()
        {
            return ToString(CultureInfo.InvariantCulture);
        }

        public string ToString(CultureInfo culture)
        {
            return suffix == "" ? value.ToString(culture) : string.Format("{0} {1}", value, suffix);
        }

        public bool Equals(DataSize other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.valueInBytes == valueInBytes && other.value.Equals(value) && Equals(other.suffix, suffix);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof (DataSize)) return false;
            return Equals((DataSize) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = valueInBytes.GetHashCode();
                result = (result*397) ^ value.GetHashCode();
                result = (result*397) ^ suffix.GetHashCode();
                return result;
            }
        }

        public static bool operator ==(DataSize left, DataSize right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(DataSize left, DataSize right)
        {
            return !Equals(left, right);
        }
    }
}
